package com.hfb.mashibing.alip8.interview.deadlock;

/**
 *问题描述：
 * 五个哲学家围着一张圆桌就餐，他们每个人面前都有一盘通心粉。由于通心粉很滑，所以需要两只筷子才能夹住，但每两个盘子之间只放着一只筷子。
 * 哲学家只有两个动作：要么就餐，要么思考。而且他们之间从不交谈。
 * 当一个哲学家饿了的时候，就拿起盘子左右两边的筷子开始就餐（不能同时拿起两只筷子）。就餐完以后，就把筷子放回盘子左右，继续思考。
 *
 *
 * 基于 synchronized 进行实现
 *
 */
public class PhilosopherQuestion_synchronized {
   public static void main(String[] args) {
     Fork fork = new Fork();
     new Philosopher("0", fork).start();
     new Philosopher("1", fork).start();
     new Philosopher("2", fork).start();
     new Philosopher("3", fork).start();
     new Philosopher("4", fork).start();
 }
}

class Philosopher extends Thread {
    private String name;
    private Fork fork;

  public Philosopher(String name, Fork fork) {
       super(name);
        this.name = name;
       this.fork = fork;
   }

    public void run() {
       while (true) {
         thinking();
          fork.takeFork();
         eating();
            fork.putFork();
      }
    }

    public void eating() {
        System.out.println("I am Eating:" + name);
       try {
           sleep(1000);// 模拟吃饭，占用一段时间资源
      } catch (InterruptedException e) {
          e.printStackTrace();
     }
    }

    public void thinking() {
      System.out.println("I am Thinking:" + name);
     try {
           sleep(1000);// 模拟思考
     } catch (InterruptedException e) {
          e.printStackTrace();
     }
    }
}

class Fork {
  /* 5只筷子，初始为都未被用 */
    private boolean[] used = { false, false, false, false, false, false };

   /* 只有当左右手的筷子都未被使用时，才允许获取筷子，且必须同时获取左右手筷子 */
  public synchronized void takeFork() {
        String name = Thread.currentThread().getName();
      System.out.println("try take : " + name);
        int i = Integer.parseInt(name);
     while (used[i] || used[(i + 1) % 5]) {
          try {
               wait();// 如果左右手有一只正被使用，等待
         } catch (InterruptedException e) {
              e.printStackTrace();
         }
        }
        used[i] = true;
     used[(i + 1) % 5] = true;
   }

    /* 必须同时释放左右手的筷子 */
  public synchronized void putFork() {
     String name = Thread.currentThread().getName();
      int i = Integer.parseInt(name);

     used[i] = false;
        used[(i + 1) % 5] = false;
      notifyAll();// 唤醒其他线程
   }
}
